Recommended Practices
On this page you will learn the different recommended practices for:
- Detecting elements
- Selecting elements by proximity
- Extracting data from Elements
- Scrolling
- Implementing assertions
Methods of Detecting Elements
You will learn:
-
What methods AskUI offers and their strengths and weaknesses
-
Use case based recommendations on what method to use
-
AI Element
- Capture elements from your screen.
-
Text
- Finds an element of class text. If you pass an argument
text('hello')
it also uses text-recognition - Limitation: Sometimes dependent on resolution, font and linebreaks
- Finds an element of class text. If you pass an argument
-
Button, textfield, checkbox, ...
all classes- Finds an element of the class
Text Detection Fails
This section describes typical problems you will run into when you try to detect text and provide solutions.
Single Character Not Detected as Text
If a single character does not get detected you have two options depending on the use case:
- Use an AI Element if the single character is not enclosed in another class like
button
.
// AI Element instead of text('<your_character>')
await aui.click().aiElement('seven-text').exec();
- Target the element that contains the single character. If you only have one
button
for example you can target the class. If you have more than onebutton
on your screen you can use a relational selector.
// Select element by finding the enclosing element
// with a relational selector
await aui.click().button()
.below().button().withText('2')
.exec();
Text In Overlay Merges with Text Below
Some overlays like dialogues do not have enough padding so the text under the overlay seems to be on the same line as the text inside the overlay. This leads to text-merging where you can not reliably target a specific text because the similarity score will never be reached.
You have a few options you can try depending on your use case:
- Maximize the dialogue/overlay if possible in your workflow, for example with a shortcut: This removes the underlying text.
- Use an AI Element as a fallback with or()
await aui.click().text('So it starts')
.or()
.aiElement('beginning-text')
.exec();
- If you just need to interact with the text and it is not important where it is exactly: Target the beginning of the text
/**
* Given this text is merged from two texts:
* 1lKBASDF Aeb567878
* First text: 1lKBASDF
* Second text: Aeb567878
*
* Target the first element
*/
await aui.click().text().containsText('1lKBASDF').exec();
Text Detection Fails Because of Linebreaks
If text is responsive, as in the example below, a linebreak is added and the text detection detects two text elements instead of one:
await aui.click()
.text('Web Automation Simplified.')
.exec();
You have to change the code to use containsText()
and match for the start of the text to remedy this:
await aui.click()
.text()
.containsText('Web Automation')
.exec();
Coherent Text is Detected as Separate Text-Elements
Sometimes coherent text is split up into two or more text-elements.
- If you need to match the exact-text, use an AI Element.
// AI element instead of text(<your_text>)
await aui.click().aiElement('thisshouldnot-text').exec();
- If you just need to interact with the text and it is not important where it is exactly: Target any part of the text
await aui.click().text("'This should not").exec();
Detection Fails on a Different Machine / in Pipeline
When the resolution changes for a workflow run on a different machine or inside a Continuous integration pipeline for example, you may encounter the following problems:
- Text linebreaks and text detection fails: See Text Detection Fails Because of Linebreaks
- Elements change shape or color during a workflow run: See Color of Same Element Changes and Duplicate Elements
Detection Is Flaky or Mislabeled
Flaky Detection Across Runs
Visual detection of elements is highly sensitive to changes in your UI, even if they are small. For example a text that you target may fail randomly on a workflow run every now and then. For example in the following picture there is a button with a 4
:
You can target it like this:
await aui.click().button().withText('4').exec();
But when you change the screen resolution, the 4
may not be recognized anymore:
You can do three things about this:
- Make the element-description more stable, for example, with a relation:
// Make element-description more stable
await aui.click().button().withText('Sign in')
.leftOf().button().withText('Login')
.exec();
- Add an AI Element with or() as a fallback:
// Fallback to ai element
await aui.click().button().withText('Sign in')
.or()
.aiElement('signin-button')
.exec();
- Add multiple fallbacks with or() and different element-descriptions:
// Add additional element-description and an ai element as fallback
await aui.click().button().withText('Sign in');
.or().button().containsText('Sign')
.or().aiElement('signin-button')
.exec();
Icon Detection Fails - Use AI Element
Detecting icons correctly is difficult because there are millions of icons available. Therefore, you may run into the problem that an icon is not detected sometimes:
Our recommended approach is to use an AI Element instead.
// AI element to target the microwave icon
// from the image above
await aui.click().aiElement('microwave-icon').exec();
Button Not Detected as Element
Sometimes a button is not detected as one. Usually this is because of low contrast or the button lacking typical characteristics of a button.
If the button is not detected but the text or label inside it, you can target the text element. Assume the 1
is recognized as a text
-element in the image above. Then you can target the button like this if there is no other text
-element 1
on the screen:
await aui.click().text('1').exec();
As not even the 1
is detected as text
in the case above, you cannot use this approach. In these cases, you can try out using an AI Element instead:
// AI element instead of button().withText()
await aui.click().aiElement('one-button').exec();
Color of Same Element Changes
AskUI can not detect color (yet). If you have an element that changes color like the button shown below:
-
Button light themed
-
Same button dark themed
You can try the following:
- Use two AI Elements together with or().
// Use two elements that compare with color
await aui.click().aiElement('light-button')
.or()
.aiElement('dark-button').exec();
Duplicate Elements
Sometimes you run into duplicate elements on an UI and you want to target a specific one. You need to make your element-description more specific in this case by doing one or all of the following:
- Add a relation
// Add relational selector to ai element
await aui.click().aiElement('submit-button')
.leftOf().button().withText('Sign up')
.exec();
- Add more element-descriptions with and()
// More specificity with and() and additional element-description
await aui.click().aiElement('submit-button')
.leftOf().button().withText('Sign up')
.and()
.button().withText('Submit')
.rightOf().button().withText('Login')
.exec();
Select Elements by Proximity
A common problem while writing instructions that one encounters is interacting with elements that share the same text.
An example can be seen when you interactively annotate your Visual Studio Code Editor. Notice that the magnifying glass icon and many other elements throughout the UI share the same name:
To ensure you’re able to instruct AskUI to select the correct element, the use of relational element-descriptions can be employed. Relational element-descriptions describe the element relative to other elements in the UI.
Selecting an Element by Visual Relation
After reading the next section you will know how to use the full power of all the relational element-descriptions. Additionally, you learn what pitfalls you can fall into and how to avoid them in the future.
We will use the Selectorshub practice page for the demonstration.
We’ll discuss the following relational element-descriptions:
above()
When you want to click on a textfield and it is above an element, like for example a button with the text Submit. You can do it with above()
. The following code snippet moves the mouse to the textfield above the Submit-button:
await aui
.click()
.textfield()
.above()
.button()
.withText('Submit')
.exec();
below()
When you want to select a textfield you can do so by finding the correct label, which is often above the textfield. The following code snippet moves the mouse to the textfield below the text Mobile Number:
await aui
.moveMouseTo()
.textfield()
.below()
.text()
.withText('Mobile Number')
.exec();
contains()
For selecting an element, that contains another element, contains()
is the right candidate. It is especially useful if you want to select a textfield with a placeholder text inside it. The text inside the textfield is annotated as an element itself.
If you have problems with selecting a specific element, always run annotate()
to create a screenshot of all the annotations or use annotateInteractively()
to see if you need to use contains()
.
The following snippet moves the mouse to a textfield based on its placeholder text First Crush which is contained in the textfield:
await aui
.moveMouseTo()
.textfield()
.contains()
.text()
.withText('First Crush')
.exec();
in()
When you want to target an element that is inside another element you can use in()
.
--------------------
| outerEl |
| -------------- |
| | innerEl | |
| -------------- |
| |
--------------------
The following code snippet moves the mouse pointer to the text of the first textfield AskUI found:
await aui
.moveMouseTo()
.text()
.in()
.textfield()
.exec();
leftOf() and rightOf()
If you want to select an element based on its location left or right of another element you have to use leftOf()
or rightOf()
respectively.